/*
struct patch
{
	DWORD from;
	DWORD to;
	std::string function_name;
	DWORD saved_address;
	DWORD called_address;
	patch(std::string name,DWORD _from,DWORD _to)
	{
		function_name = name;
		from = _from;
		to = _to;
	}
};



patch patches[] = {
				  patch(std::string("Init"), 0x00502DC3,0x00506990 ),
				  //patch(std::string("Render"), 0x005060A8,0x00505A40)
					patch(std::string("Render"), 0x005030FD,0x00503187)
				  };
DWORD dll_call_address = 0x0088518B;
DWORD dll_hook_address = 0x0088BADD ;
std::string dll_name("OgreDwarf");
DWORD buf_size;
long dll_load_code_address;

DWORD _RenderCall = 0x005060A8;
DWORD _EmptySpace = 0x008C3100;
long  _ReturnJump;
DWORD _CallOffset = _EmptySpace - _RenderCall + 5; // for the call operand

uchar _CallProc[5] = { 0xE8,0x6F,0xD0,0x3B,0};


//#define __ASMDEB_LOAD
//#define __ASMDEB_CALL

#pragma pack(push,1)
union inc{
	struct
	{ 
		uchar a[30];
		long function_address;
		uchar b[4];
		long dll_name_address;
		uchar c[2];
		long LoadLibrary_adress;
		uchar d[1];
		long proc_name_adress;
		uchar e[3];
		long GetProcAdress_adress;
		uchar f[1];
		long function_address2;
		uchar g[2];
		long function_address3;
		uchar h[1];
		long render_jump_offset;
	} st;
	uchar data[76];
} ;
inc InjectCode;
#pragma pack(pop)	


uchar data[78] = {	'O','g','r','e','D','w','a','r','f', 0 , 0 , 0, // DLL_name
					'R','e','n','d','e','r', 0 , 0 , 0 , 0 , 0 , 0, // proc_name;
					 0 , 0 , 0 , 0 ,								// DLL_func_address
					 0x60,											//pusha
					0x83,0x3d, 0x18 , 0x31 , 0x8c , 0 , 0 ,			// cmp DLL_func_adress,0
					0x75,0x1C,										// jnz +1Ch
					0x68, 0 , 0x31 , 0x8c , 0 ,						// push DLL_name
					0xFF,0x15, 0xA0 , 0x40 , 0x8c , 0 ,				// call ds:LoadLibraryA
					0x68, 0x0C , 0x31 , 0x8c , 0 ,					// push proc_name
					0x50,											// push eax
					0xFF, 0x15, 0x70 , 0x41 , 0x8c , 0 ,				// call ds:GetProcAdressA
					0xA3, 0x18 , 0x31 , 0x8c , 0,					// mov eax DLL_func_adress
					0xFF,0x15, 0x18 , 0x31 , 0x8c , 0 ,				// call DLL_func_adress
					0x61,											// popa
					0xEB, 0xf4 , 0x28 , 0xC4 , 0xFF					// jmp Render
					};
/*
	uchar DLL_name[12];
	uchar proc_name[12];
	FARPROC DLL_func_address;
	struct 	{		uchar cmp[2],address[4],op;	} cmp_struct;	// 83,3d,xx,xx,xx,xx,00
					uchar jnz[2];								// 74,??
	struct	{		uchar push,address[4];	} push_dll;			// 68,xx,xx,xx,xx
	struct	{		uchar call[2],address[4];	} call_load;	// FF,15,xx,xx,xx,xx
	struct  {
					uchar push,address[4];	} push_proc;		// 68,xx,xx,xx,xx
					uchar push_eax;								// 50
	struct{			uchar call[2],address[4];	} call_get_proc;// FF,15,xx,xx,xx,xx
	struct{			uchar mov,address[4];	} mov_eax_proc;		// A3,xx,xx,xx,xx
	struct{			uchar call,address[4];	} call_proc;		// FF,15,xx,xx,xx,xx
	struct{			uchar jmp,address[4];	} render_jump;		// E9,xx,xx,xx,xx,xx
};
*/

/*

typedef unsigned short ushort;

#pragma pack(push,1)
struct function_ref
{
	uchar name[12];
	DWORD address;
};


struct function_call
{
#ifdef __ASMDEB_CALL
	uchar int3;
#endif
	uchar pusha;
	ushort cmp;
	DWORD address1;
	uchar op;
	uchar jz;
	uchar offset1;
	ushort call;
	DWORD address2;
	uchar popa;
	uchar jmp;
	long original_offset;
	function_call(DWORD proc_ref_address,long original_function_address,long code_loc)
	{
#ifdef __ASMDEB_CALL
	int3 =0xcc;
#endif		
		pusha= 0x60; popa = 0x61; cmp = 0x3d83; op = 0; call = 0x15FF; jz = 0x74; jmp = 0xE9;
		offset1 = 6;
		address1 = address2 = proc_ref_address;
		original_offset = original_function_address - (code_loc+sizeof(function_call));
	}
};

struct dll_load
{
#ifdef __ASMDEB_LOAD
	uchar int3;
#endif
	uchar pusha;
	uchar push_d_n;
	DWORD dll_add;
	ushort call;
	DWORD LL_address;
	uchar push_eax;
	uchar mov_ebx;  // BB
	DWORD fr_table; 
	uchar pop_eax;
	uchar push_eax2;
	uchar push_ebx;
	uchar push_eax3;
	ushort call2;
	DWORD GPA_address;
	ushort mov_eax;
	uchar offs;
	ushort add_ebx;
	uchar val;
	ushort cmp_ebx;
	uchar op;
	ushort jnzback;
	uchar pop_eax2;
	uchar popa;
	uchar jmp;
	long original_offset;

	dll_load(long base_address,long ref_tab_address,long call_loc, long insertion_address,DWORD ll_address,DWORD gpa_address)
	{
#ifdef __ASMDEB_LOAD
	int3 =0xcc;
#endif		
		pusha = 0x60;popa = 0x61; push_d_n = 0x68; call = call2 = 0x15FF;
		mov_ebx = 0xBB; pop_eax = 0x58; push_eax=push_eax2 = push_eax3 = 0x50;
		push_ebx = 0x53; mov_eax = 0x4389; offs = 0x0C; val = 0x10; op = 0;
		add_ebx = 0xC383; cmp_ebx = 0x3B83; jnzback = 0xEB75; jmp =0xE9;pop_eax2 = 0x58;
		GPA_address = gpa_address;
		LL_address = ll_address;
		original_offset = call_loc - insertion_address - sizeof(dll_load);
		dll_add = base_address;
		fr_table = ref_tab_address;

	}
};

struct call_thunk
{
	uchar callop;
	long offset;
	call_thunk(long loc,long target)
	{
		offset = target - loc - 5;
		callop = 0xe8;
	}
};

#pragma pack(pop)



DWORD EstimatePatchSize()
{
	DWORD length = dll_name.length()+1;
	length+= sizeof(patches)/sizeof(patch) * sizeof(function_ref)+4;
	length+= sizeof(dll_load);
	length+= sizeof(patches)/sizeof(patch) * sizeof(function_call);
	return length;
}

uchar *ProcessPatches(long insertion_address)
{
	std::vector<function_ref> references;
	std::vector<function_call> dispatches;

	int length = 0;
	length = dll_name.length()+1; 
	long references_address = insertion_address+length;
	function_ref f;
	for (int i = 0; i < sizeof(patches)/sizeof(patch); ++i)
	{
		f.address = 0;
		strncpy((char*)f.name,patches[i].function_name.data(),11);
		references.push_back(f);
		patches[i].saved_address = insertion_address + length + 12; 
		length += 16;
	}
	length+=4; //padding for empty ref check
	dll_load_code_address = insertion_address+length;
	dll_load insertion_code(insertion_address,references_address,dll_hook_address,dll_load_code_address,0x8c40A0 ,0x8c4170);
	length += sizeof(insertion_code);
	for (int i = 0; i < sizeof(patches)/sizeof(patch); ++i)
	{
		dispatches.push_back(function_call(patches[i].saved_address,patches[i].to,insertion_address+length));
		patches[i].called_address = insertion_address+length;
		length+= sizeof(function_call);
		
	}
	uchar *buf =(uchar*) malloc(length);
	uchar *cbuf_ptr = buf;
	memcpy(cbuf_ptr,dll_name.data(),dll_name.length()+1);
	cbuf_ptr+=dll_name.length()+1;
	for (std::vector<function_ref>::iterator i = references.begin(); i != references.end(); ++i, cbuf_ptr+= sizeof(function_ref))
		memcpy(cbuf_ptr,(void*)&(*i),sizeof(function_ref));
	*((DWORD*)cbuf_ptr) = 0;
	cbuf_ptr+=4;
	memcpy(cbuf_ptr,&insertion_code,sizeof(insertion_code));
	cbuf_ptr += sizeof(insertion_code);
	for (std::vector<function_call>::iterator i = dispatches.begin(); i != dispatches.end(); ++i, cbuf_ptr+= sizeof(function_call))
		memcpy(cbuf_ptr,(void*)&(*i),sizeof(function_call));

	return buf;
}

*/

// In WinMain

/*
	DWORD p_size = EstimatePatchSize();

	DWORD oldProtect;
	result = VirtualProtectEx(pi.hProcess,(LPVOID)_EmptySpace,p_size,PAGE_EXECUTE_READWRITE,&oldProtect);
	if (result == 0)
	{
		FormatLastError();
		TerminateProcess(pi.hProcess,0);
		return 1;
	}
	DWORD i_address = _EmptySpace;

	uchar *buf = ProcessPatches(i_address);
	SIZE_T bWritten;
	result = WriteProcessMemory(pi.hProcess,(LPVOID)_EmptySpace,(LPVOID)buf,p_size,&bWritten);
	if (result == 0)
	{
		FormatLastError();
		TerminateProcess(pi.hProcess,0);
		return 1;
	}
	if (bWritten != p_size ) 
	{
		MessageBox(NULL,"Injecting dll dispatch block failed!","Error",MB_OK);
		TerminateProcess(pi.hProcess,0);
		return 1;
	}
	
	

	call_thunk thunk(dll_call_address,dll_load_code_address);
	result = VirtualProtectEx(pi.hProcess,(LPVOID)dll_call_address,5,PAGE_EXECUTE_READWRITE,&oldProtect);
	if (result == 0)
	{
		FormatLastError();
		TerminateProcess(pi.hProcess,0);
		return 1;
	}
	result = WriteProcessMemory(pi.hProcess,(LPVOID)dll_call_address,(LPVOID)&thunk,5,&bWritten);
	if (result == 0)
	{
		FormatLastError();
		TerminateProcess(pi.hProcess,0);
		return 1;
	}
	if (bWritten != 5 ) 
	{
		MessageBox(NULL,"Patching dll load hook failed!","Error",MB_OK);
		TerminateProcess(pi.hProcess,0);
		return 1;
	}


	for (int i = 0; i < sizeof(patches)/sizeof(patch); ++i)
	{
		call_thunk thunk(patches[i].from,patches[i].called_address);
		result = VirtualProtectEx(pi.hProcess,(LPVOID)patches[i].from,5,PAGE_EXECUTE_READWRITE,&oldProtect);
		if (result == 0)
		{
			FormatLastError();
			TerminateProcess(pi.hProcess,0);
			return 1;
		}
		result = WriteProcessMemory(pi.hProcess,(LPVOID)patches[i].from,(LPVOID)&thunk,5,&bWritten);
		if (result == 0)
		{
			FormatLastError();
			TerminateProcess(pi.hProcess,0);
			return 1;
		}
		if (bWritten != 5 ) 
		{
			std::string res = std::string("Patching for ") + patches[i].function_name + std::string(" failed!");
			MessageBox(NULL,res.data(),"Error",MB_OK);
			TerminateProcess(pi.hProcess,0);
			return 1;
		}
	}
	
	free(buf);*/
